实战 | C# 中使用YOLOv11实现实例分割 (步骤 + 源码)

导  读

本文主要介绍在C#中使用YOLOv11实现实例分割,并给详细步骤和源码。

C# YOLO11实例分割——本文实现效果:

实现步骤

关于YOLO11和YoloSharp的介绍请参考下面两篇文章,有详细步骤:

实战 | C#中使用YoloV8和OpenCvSharp实现目标检测 (步骤 + 源码)_yolosharp-CSDN博客

实战 | C# 中使用YOLOv11实现目标检测 (步骤 + 源码)_c# yolo-CSDN博客

检测模型可以试下载官方模型,也可以使用自己训练的模型,本文使用yolo11n-seg.pt,然后转换为onnx模型yolo11n-seg.onnx,转换代码如下:

from ultralytics import YOLO

# Load a model
model = YOLO("yolo11n-seg.pt")  # load an official model

# Export the model
model.export(format="onnx")
 

注意安装ultralytics最新版本,避免模型转换失败!

代码部分,没有UI的代码和目标检测部分基本一致,主要是这句

var results = predictor.Segment(srcImg.ToMemoryStream());

其中原来的Detect变成了Segment,检测变分割,使用下面代码保存得到官方的结果图

 using var image = SixLabors.ImageSharp.Image.Load(pathList[imgIndex]);
 using var ploted = results.PlotImage(image);
 ploted.Save("cc.jpg");

后面改成了WinForm版本,绘制时需要获取掩码(mask)自行绘制,这部分核心代码在ImgSegment函数中:

public Mat ImgSegment(Mat srcImg)
{
    Mat img = srcImg.Clone();
    //Mat img = Mat.Zeros(srcImg.Size(), MatType.CV_8UC3);
    var results = predictor.Segment(srcImg.ToMemoryStream());
    for (int index = 0; index < results.Count; index++)
    {
        Cv2.Rectangle(img, new OpenCvSharp.Point(results[index].Bounds.Left, results[index].Bounds.Top), new OpenCvSharp.Point(results[index].Bounds.Right, results[index].Bounds.Bottom), new Scalar(255, 0, 255), 2);
        string text = results[index].Name.Name + ":" + results[index].Confidence.ToString("F2");
        Cv2.PutText(img, text, new OpenCvSharp.Point(results[index].Bounds.Left, results[index].Bounds.Top + 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 255, 0), 2);

        //用At方法访问像素值
        int x0 = results[index].Bounds.X;
        int y0 = results[index].Bounds.Y;
        for (int i = 0; i < results[index].Mask.Height; i++)
        {
            for (int j = 0; j < results[index].Mask.Width; j++)
            {
                if (results[index].Mask[i, j] > 0.5)
                    img.At<Vec3b>(i + y0, j + x0) = colors[index % 6]; //RGB彩色图像素值改变
            }
        }
    }

    //using var image = SixLabors.ImageSharp.Image.Load(pathList[imgIndex]);
    //using var ploted = results.PlotImage(image);
    //ploted.Save("cc.jpg");

    return img;
}

然后最终效果如下:

完整代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using Compunet.YoloSharp;
using Compunet.YoloSharp.Plotting;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using SixLabors.ImageSharp;


namespace YoloSharp_Segment
{
    public partial class Form1 : Form
    {
        //Mat srcImg = new Mat();
        static YoloPredictor predictor = new YoloPredictor("yolo11n-seg.onnx");
        string[] pathList;
        Vec3b[] colors = {new Vec3b(0, 255, 0), new Vec3b(0, 0, 255), new Vec3b(255, 0, 0), 
                                   new Vec3b(0, 255, 255), new Vec3b(255, 255, 0), new Vec3b(255, 0, 255) };
        int imgIndex = 0;
        public Form1()
        {
            InitializeComponent();
            predictor.Configuration.SuppressParallelInference = true;
            predictor.Configuration.KeepAspectRatio = true;
            predictor.Configuration.Confidence = 0.3F;
        }

        public Mat ImgSegment(Mat srcImg)
        {
            Mat img = srcImg.Clone();
            //Mat img = Mat.Zeros(srcImg.Size(), MatType.CV_8UC3);
            var results = predictor.Segment(srcImg.ToMemoryStream());
            for (int index = 0; index < results.Count; index++)
            {
                Cv2.Rectangle(img, new OpenCvSharp.Point(results[index].Bounds.Left, results[index].Bounds.Top), new OpenCvSharp.Point(results[index].Bounds.Right, results[index].Bounds.Bottom), new Scalar(255, 0, 255), 2);
                string text = results[index].Name.Name + ":" + results[index].Confidence.ToString("F2");
                Cv2.PutText(img, text, new OpenCvSharp.Point(results[index].Bounds.Left, results[index].Bounds.Top + 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 255, 0), 2);

                //用At方法访问像素值
                int x0 = results[index].Bounds.X;
                int y0 = results[index].Bounds.Y;
                for (int i = 0; i < results[index].Mask.Height; i++)
                {
                    for (int j = 0; j < results[index].Mask.Width; j++)
                    {
                        if (results[index].Mask[i, j] > 0.5)
                            img.At<Vec3b>(i + y0, j + x0) = colors[index % 6]; //RGB彩色图像素值改变
                    }
                }
            }

            //using var image = SixLabors.ImageSharp.Image.Load(pathList[imgIndex]);
            //using var ploted = results.PlotImage(image);
            //ploted.Save("cc.jpg");

            return img;
        }


        private void buttonOpenFolder_Click(object sender, EventArgs e)
        {
            //OpenFileDialog ofd = new OpenFileDialog();  //创建打开对话框对象
            //ofd.Title = "请选择打开的文件";  //设置对话框标题
            //ofd.Multiselect = true; //设置文件是否可以多选
            //ofd.InitialDirectory = @"./";  //设置初始打开目录
            ////文本文件(*.txt) | *.txt | 所有文件(*.*) | *.*””
            //ofd.Filter = "图片文件|*.jpg;*.png;*.bmp;*.jpeg";  //打开jpg图片文件和png 图片文件
            //ofd.ShowDialog();  //显示对话框
            //string path = ofd.FileName;  // 选择文件的全路径
            //if (path == "")  //异常处理,点击取消时,空路径报错
            //{
            //    return;
            //}
            ////显示打开图片
            //srcImg = Cv2.ImRead(path);
            //pictureBoxSrc.Image = srcImg.ToBitmap();

            //if(pathList.Length > 0) 
            //    Array.Clear(pathList, 0, pathList.Length);
            using (FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog())
            {
                if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
                {
                    string folderPath = folderBrowserDialog.SelectedPath;
                    pathList = Directory.GetFiles(folderPath, "*.*")
                                                  .Where(file => file.EndsWith(".jpg") || file.EndsWith(".png") || file.EndsWith(".bmp"))
                                                  .ToArray();
                }
            }
            if (pathList.Length == 0)
                return;
            imgIndex = 0;
            Mat img = Cv2.ImRead(pathList[0]);
            pictureBoxSrc.Image = img.ToBitmap();
            Mat resImg = ImgSegment(img);
            pictureBoxResult.Image = resImg.ToBitmap();
        }

        private void buttonPreOne_Click(object sender, EventArgs e)
        {
            if (imgIndex == 0)
                imgIndex = 0;
            else
            {
                imgIndex--;
            }
            Mat img = Cv2.ImRead(pathList[imgIndex]);
            pictureBoxSrc.Image = img.ToBitmap();
            Mat resImg = ImgSegment(img);
            pictureBoxResult.Image = resImg.ToBitmap();
        }

        private void buttonNextOne_Click(object sender, EventArgs e)
        {
            if (imgIndex == pathList.Length-1)
                imgIndex = pathList.Length - 1;
            else
            {
                imgIndex++;
            }
            Mat img = Cv2.ImRead(pathList[imgIndex]);
            pictureBoxSrc.Image = img.ToBitmap();
            Mat resImg = ImgSegment(img);
            pictureBoxResult.Image = resImg.ToBitmap();
        }
    }
}